/********************************************************************
	created:	
	created:	
	file base:	convert
	file ext:	h
	author:		Kim,Jong-Kook
	
	purpose:	
	history:
		20110418 add Utf8ToUnicode(const char*, const size_t* )
*********************************************************************/
#ifndef _JK_CONVERT_H_
#define _JK_CONVERT_H_
#include <string>
#include <string.h>

#if defined(_MSC_VER) && (_MSC_VER <= 1200)
#define STD_PUSHBACK(obj,val) obj.insert(obj.begin(),val)
#else
#define STD_PUSHBACK(obj,val) obj.push_back(val)
#endif 

struct Convert
{

   static unsigned char HexToByte(const char c)
   {
      if(c>='0' && c<='9') return c-'0';
      if (c>='A' && c<='F') return c-'A'+10;
      if (c>='a' && c<='f') return c-'a'+10;
      return 0;        // not Hex digit
   }

   static std::wstring Utf8ToUnicode(const char* utf8, const size_t* size)
   {
	   std::wstring ret;
	   wchar_t w = 0;
	   int bytes = 0;
	   wchar_t err = 0xFFFD;//L'?';/*"\uFFFD"*/
	   size_t nSize = size ? *size:strlen(utf8);
	   for (size_t i = 0; i < nSize; i++)
	   {
		   unsigned char c = (unsigned char)utf8[i];
		   if (c <= 0x7f)
		   {//first byte
			   if (bytes)
			   {
				   STD_PUSHBACK(ret, err);
				   bytes = 0;
			   }
			   STD_PUSHBACK(ret, (wchar_t)c);
		   }
		   else if (c <= 0xbf)
		   {//second/third/etc byte
			   if (bytes)
			   {
				   w = ((w << 6)|(c & 0x3f));
				   bytes--;
				   if (bytes == 0)
					   STD_PUSHBACK(ret, w);
			   }
			   else
				   STD_PUSHBACK(ret, err);
		   }
		   else if (c <= 0xdf)
		   {//2byte sequence start
			   bytes = 1;
			   w = c & 0x1f;
		   }
		   else if (c <= 0xef)
		   {//3byte sequence start
			   bytes = 2;
			   w = c & 0x0f;
		   }
		   else if (c <= 0xf7)
		   {//3byte sequence start
			   bytes = 3;
			   w = c & 0x07;
		   }
		   else
		   {
			   STD_PUSHBACK(ret, err);
			   bytes = 0;
		   }
	   }
	   if (bytes)
		   STD_PUSHBACK(ret, err);
	   return ret;
   }

   static std::wstring Utf8ToUnicode(std::string& utf8)
   {
	   size_t size = utf8.size();
	   return Utf8ToUnicode(utf8.c_str(), &size);
   }
   
   inline static std::string UnicodeToUtf8(const wchar_t* uni)
   {
      return UnicodeToUtf8(std::wstring(uni));
   }
   static std::string UnicodeToUtf8(std::wstring& uni)
   {
      std::string ret;
      for( size_t i=0; i<uni.size(); i++)
      {
         wchar_t w = uni[i];

         if (w <= 0x7f)
         {
            STD_PUSHBACK(ret, (char)w);
         }
         else if (w <= 0x7ff)
         {
            STD_PUSHBACK(ret,(0xc0 | ((w >> 6)& 0x1f)));
            STD_PUSHBACK(ret,(0x80| (w & 0x3f)));
         }
         else if (w <= 0xffff)
         {
            STD_PUSHBACK(ret,(0xe0 | ((w >> 12)& 0x0f)));
            STD_PUSHBACK(ret,(0x80| ((w >> 6) & 0x3f)));
            STD_PUSHBACK(ret,(0x80| (w & 0x3f)));
         }
         else if (w <= 0x10ffff)
         {
            STD_PUSHBACK(ret,(0xf0| (((unsigned int)w >> 18)& 0x07)));
            STD_PUSHBACK(ret,(0x80| ((w >> 12) & 0x3f)));
            STD_PUSHBACK(ret,(0x80| ((w >> 6) & 0x3f)));
            STD_PUSHBACK(ret,(0x80| (w & 0x3f)));
         }
         else
            STD_PUSHBACK(ret, '?');
      }
      return ret;
   }
};

#endif/*_JK_CONVERT_H_*/
